#title: Ioc - Annotation 加载器
#index:0,1
#author:wendal(wendal1985@gmail.com)
#author:zozoh(zozohtnt@gmail.com)
--------------------------------------------------------------------------------------------------------
为什么需要 Ioc 注解加载器

	无论是 XML 还是 JSON，都需要你创建一个新的配置文件，在里面描述你的对象依赖关系。一般的来说，
	一个应用大多数的对象依赖关系，是固定的，即，在项目发布以后是不必调整的。如果将这些依赖关系通通写到
	配置文件中，颇有点"脱了裤子放屁"的感觉，最理想的情况是，将可能变动的依赖关系写到配置文件里，而将不怎么
	会变动的依赖关系写成 Java 的注解 ({/Annotation})， 如果能这样的话，一切就圆满了。

	{*但是，真的可以吗？}

	我可以负责任的告诉你，完全是可以滴 ^_^

	首先这篇文章，会详细讲解一下如果通过注解来配置你的容器对象，而 [loader_combo.man Ioc 复合加载器]一篇，
	将会告诉你如何组合多个加载器，这样你就可以把你的对象依赖关系分别写到 xml,json,以及 Java 注解里，组合
	使用了。

--------------------------------------------------------------------------------------------------------
如何使用 AnnotationIocLoader

	同 JsonLoader 一样，你可以直接 new 一个 AnnoationIocLoader
	{{{<Java>
	Ioc ioc = new NutIoc(new AnnotationIocLoader("com.you.app.package0", "com.you.app.package1"));
	}}}

	当然在 Nutz.Mvc 中，你可以通过 IocProvider 来初始化 Ioc 容器，所以你可以在你的 MainModule 上这么声明
	{{{<Java>
	@IocBy(type = AnnotationIocProvider.class, 
	       args = { "com.you.app.package0",
	                "com.you.app.package1"})
	public class MainModule {
	    ....
	}}}

	这样，你在
	
	 * com.you.app.package0
	 * com.you.app.package1
	
	这两包下，所有声明了 {* @IocBean} 这个注解的对象，都会被认为是容器对象。是的，通过注解 {* @IocBean}， 
	AnnotationIocLoader 就能辨别你指定的包中，哪些类是可以交由容器管理的。
	
	那么，{* @IocBean}里面还能声明什么信息，我怎么为我的容器对象设置注入内容呢？ 请继续看下面内容 ^_^

--------------------------------------------------------------------------------------------------------
指定对象的名称

	任何一个 Ioc 容器管理的对象，都必须有一个名字，以便通过:
	{{{<Java>
	MyObject obj = ioc.get(MyObject.class, "myObjectName");
	}}}
	来获取对象。
	
	因此，你可以为你的对象这么声明:
	{{{<Java>
	@IocBean(name="myObjectName")
	public class MyObject {
		...
	}}}
	
	如果你的对象名字为你对象类名的首字母小写形式，你可以省略名字这个属性, 即
	{{{<Java>
	@IocBean
	public class MyObject {
		...
	}}}
	同
	{{{<Java>
	@IocBean(name="myObject")
	public class MyObject {
		...
	}}}
	效果是一样的。
	
	还有另外一种方法，你可以为你的对象声明一个单独注解：
	{{{<Java>
	@InjectName("myObjectName")
	@IocBean
	public class MyObject {
		...
	}}}
	列位，看到这里，可能有人会问了，这不是脱裤子放屁吗？ @IocBean 可以有 name 属性，而你又搞了一个
	@InjectName 注解专门声明名字，你到底打算让我们用哪一个？你逗我们玩哪？
	
	首先，我得跟大家声明一下，这的确是一点点历史问题，原先的 @InjectName 是给 Nutz.Mvc 用的，它如果发现
	了子模块声明了这个属性，就交付给 Ioc 容器管理。 后来，我们发现，介个名字和 @IocBean 的名字必须是相同的，
	所以在 AnnotationIocLoader 里，我们做了如下优先级的判断:
	 # 如果发现 @IocBean 有 name 属性，这个对象就采用这个名字
	 # 如果没有 @IocBean(name="xxxx")，哪么就看看有没有声明了 @InjectName
	 # 还没有的话，就用对象的类名首字母小写形式作为这个对象的名称
	
	因此对于一个 Nutz.Mvc 的模块类来说， @InjectName + @IocBean 是一个比较方便的写法。
	
	但是现在我也承认， @IocBean 的 name 属性有点多余，或者 @InjectName 有点多余。 但是由于是过了几个版本以后
	才认识到的这个问题，所以我想，不如就留着这个设计，作为 Nutz 这个项目的一段 {*盲肠}， 希望列位看官理解
	我们的苦衷，毕竟我们宣称了接口不会有重大变动之后，就要拿掉这个盲肠话，仿佛自己打了一记自己嘴巴。
	因此，人类的劣根性导致我们这么安慰自己：“没事没事，这个设计虽然有一点点臃肿，但是没人让人更难用，
	也过得去啦 -_-!”
--------------------------------------------------------------------------------------------------------
不要单例?

	默认的，Ioc 容器管理的对象都是单例的，你如果不想单例，你可以:
	{{{<Java>
	@IocBean(name="myObject", singleton=false)
	public class MyObject {
		...
	}}}

--------------------------------------------------------------------------------------------------------
为对象传递构造函数
	
	当然 @IocBean 这点是不够，很多对象注入的时候，需要为构造函数声明信息，你可以这样：
	{{{<Java>
	@IocBean(name="myObject", args={"a string", "refer:anotherObject", true, 234})
	public class MyObject {
		...
	}}}
	看，简单不？ 你的构造函数有多少个参数，你就一并在 "args" 属性里声明就好了， 那么你都能注入什么呢？

	它注入的值同字段注入的值描述方式相同，请继续看下面一节，我们有更详细的解释

--------------------------------------------------------------------------------------------------------
为对象的字段注入
	
	这个更加简单，比如:
	{{{<Java>
	@IocBean
	public class MyObject {
		
		@Inject("abcc")
		private String name;
		
		@Inject("true")
		private boolean live;
		
		@Inject("refer:another")
		private AnotherObject obj;
		
		...
		
	}}}
	
	那么你到底能注入什么呢？ 感兴趣的同学可以看这里：[injecting.man 你都可以注入什么]。
	当然，同 Json 的方式有点不同，你这里直接写 "refer:xxxx" 或者 "env:xxxx" 就好了。下面是一个列表
	
	|| @Inject("refer:objName")            ||  注入容器其他对象的引用 ||
	|| @Inject("refer:$ioc")               ||  容器自身 ||
	|| @Inject("refer:$Name")              ||  对象的名称，即你在 @InjectName 或者 @IocBean 里声明的 name ||
	|| @Inject("refer:$Context")           ||  容器上下文 ||
	|| @Inject("env:JAVA_HOME")            ||  系统环境变量 ||
	|| @Inject("sys:user.home")            ||  虚拟机属性 ||
	|| @Inject("jndi:jndiName")            ||  JNDI 资源 ||
	|| @Inject("file:/home/zzh/abc.txt")   ||  文件对象 ||
	|| @Inject("java:com.my.SomeClass.staticPropertyName")   || 调用某 JAVA 类的静态属性 ||
	|| @Inject("java:com.my.SomeClass.someFunc")             || 调用某 JAVA 类的静态函数 ||
	|| @Inject("java:com.my.SomeClass.someFunc("p1",true)")  || 调用某 JAVA 类的带参数的静态函数 ||
	|| @Inject("java:$xh")                                   || 获得容器对象 xh ，相当于 "refer:xh" ||
	|| @Inject("java:$xh.name")                              || 容器对象某个属性 ||
	|| @Inject("java:$xh.getXXX()")                          || 容器对象某个方法的返回值 ||
	|| @Inject("$xh.getXXX("some string", true, 34)")        || 容器对象某个方法的返回值 ||
	
	兼容性改变, 如果你硬要注入一个常量(例如true,false,字符串), 那么写成 ":true" ":false" ":hi"
	
	基本上，看到上面的表格，你同时也能完全明白怎么 [#为对象传递构造函数]，不是吗？
--------------------------------------------------------------------------------------------------------
声明对象的事件

	在 Nutz.Ioc 容器里，一个对象有三种事件：
	 # create - 当对象被创建时触发
     # fetch - 当对象被从容器中取出时触发
	 # depose - 当对象被销毁时触发
	同 JSON 配置一样， Annotation 方式的配置也允许你声明这三种事件的处理方式
	{{{<JAVA>
	@IocBean(
		create = "init",
		fetch = "com.myapp.MyObjectOnFetchTrigger",
		depose = 'onDepose'
	)
	public class MyObject {
		...
	}}}
	同 JSON 的配置方式相同的是，你可以为该对象处理该事件的一个函数，比如上面的例子，MyObject 需要有一个函数
	{*init} 来处理创建时的事件，还需要一个函数 {*onDepose} 来处理注销时的事件。当然这两个函数不能时静态的，
	也不能有任何参数。 对一个事件，你还可以声明一个 {*IocEventTrigger} 的实现类，来处理一个事件。比如上面的例子，
	我们就用 com.myapp.MyObjectOnFetchTrigger 来处理 fetch 事件的。

	看到这里，可能有的同学会弱弱的问了，这个功能到底是干虾米滴？ 我认为所有需要问这个问题的同学都可以无视这个
	功能，因为你根本不需要它。但是如果你想在对象创建的时候，做点初始化工作，比如为某几个字段设设值；或者你希望
	在容器注销你的对象时，你想同时释放点资源，比如数据连接池对象被销毁时，你需要释放一下池内的连接；又或者你想
	为你的对象做一个计数，每次从容器获取的时候，计数＋1，用来统计你对象被使用的频率，我想你也很需要 fetch 这个
	事件。无论你采用对象的函数，还是自己实现 IocEventTrigger 这个接口，你会拿到容器里的对象实例，然后你想做什么
	完全随你喽 :)


--------------------------------------------------------------------------------------------------------
如果要注入的字段在超类怎么办
	
	答
	{{{<Java>
	@IocBean(fields={"dao"})
	public AbcService extends Service {
		...
	}}}
	
	比如上例，你的 AbcService 从 Service 继承，但是 Serivce 有一个私有字段为 "private Dao dao"， 你怎么描述
	它的注入呢？ 你可以通过 @IocBean 注解提供 fields 属性，描述你要注入超类那个字段，比如上面的例子，我们会
	为超类的 "dao" 字段注入一个名为 "dao" 容器对象。 

	但是，如果我想注入的容器对象同超类的那个字段名字不一样怎么办？ 或者我不打算注入一个容器对象，我想注入一个
	字符串，或者布尔值怎么办？ 呵呵，抱歉，截止到现在，我们还没有解决这个问题，不过很快我们会给出一个设计，
	并且我可以负责的说，给出新的设计一定会兼容现在的这个用法的。

--------------------------------------------------------------------------------------------------------
工厂方法

	{{{<Java>
	@IocBean(factory="net.wendal.mqtt.MqttAbcServiceFactory#create", args={"refer:dao"})
	public class AbcService extends Service {
		...
		
	}
	
	// 无任何注解
	public class MqttAbcServiceFactory {
		public static AbcService create(Dao dao) {
			return new XXXXAbcService(dao);
		}
	}
	}}}
	
	通过其他bean生成此bean, 类似于spring的factory-bean功能
	
	{{{
	@IocBean(factory="$snakerConfigure#build")
	public class SnakerService{}
	
	
	@IocBean(name="snakerConfigure")
	public class SnakerConfigure {
		public SnakerService build() {
			return ....;
		}
	}
	}}}
	
	